use std::cell::{RefCell, RefMut};
use std::ops::Deref;
use std::rc::Rc;
use std::thread::Thread;
use crate::class_file::byte_data_reader::ByteDataReader;
use crate::heap::vm_heap::VMHeap;
use crate::instruction::instruction::Instruction;
use crate::class::vm_class_constant_info::VMClassConstantInfoEnum;
use crate::vm_thread::{VMFrame, VMThread};
use crate::vm_val::{VMValDouble, VMValEnum, VMValFloat, VMValInteger, VMValLong};

pub struct ldc2_w {
    pub index: u16,
}

impl Instruction for ldc2_w {
    fn read_operands(&mut self, frame: Rc<RefCell<VMFrame>>) {
        self.index = frame.deref().borrow_mut().read_u16();
    }

    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        let current_vm_class = &frame.borrow().current_vm_class;
        let constant_pool = current_vm_class.constant_pool.borrow();
        let constant_info_option = constant_pool.get(self.index as usize);
        if constant_info_option.is_none() {
            panic!("{},{},{},常量获取失败", file!(), line!(), self.index);
        }
        match constant_info_option.unwrap().deref() {
            VMClassConstantInfoEnum::VMClassConstantInfoInteger { val } => {
                frame.borrow().operand_stack.borrow_mut().push(VMValEnum::VMValInteger {
                    val: VMValInteger { num: val.val }
                })
            }
            VMClassConstantInfoEnum::VMClassConstantInfoLong { val } => {
                frame.borrow().operand_stack.borrow_mut().push(VMValEnum::VMValLong {
                    val: VMValLong { num: val.val }
                })
            }
            VMClassConstantInfoEnum::VMClassConstantInfoFloat { val } => {
                frame.borrow().operand_stack.borrow_mut().push(VMValEnum::VMValFloat {
                    val: VMValFloat { num: val.val }
                })
            }
            VMClassConstantInfoEnum::VMClassConstantInfoDouble { val } => {
                frame.borrow().operand_stack.borrow_mut().push(VMValEnum::VMValDouble {
                    val: VMValDouble { num: val.val }
                })
            }
            _ => {
                panic!("{},{},{},常量类型异常", file!(), line!(), self.index);
            }
        }
    }

    fn to_string(&self) -> String {
        String::from("ldc2_w")
    }
}

pub struct ldc {
    pub index: u8,
}

impl Instruction for ldc {
    fn read_operands(&mut self, frame: Rc<RefCell<VMFrame>>) {
        self.index = frame.deref().borrow_mut().read_u8();
    }

    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {

        let current_vm_class = &frame.borrow().current_vm_class;
        let constant_pool = current_vm_class.constant_pool.borrow();
        let constant_info_option = constant_pool.get(self.index as usize);
        if constant_info_option.is_none() {
            panic!("{},{},{},常量获取失败", file!(), line!(), self.index);
        }
        match constant_info_option.unwrap().deref() {
            VMClassConstantInfoEnum::VMClassConstantInfoInteger { val } => {
                frame.borrow().operand_stack.borrow_mut().push(VMValEnum::VMValInteger {
                    val: VMValInteger { num: val.val }
                })
            }
            VMClassConstantInfoEnum::VMClassConstantInfoLong { val } => {
                frame.borrow().operand_stack.borrow_mut().push(VMValEnum::VMValLong {
                    val: VMValLong { num: val.val }
                })
            }
            VMClassConstantInfoEnum::VMClassConstantInfoFloat { val } => {
                frame.borrow().operand_stack.borrow_mut().push(VMValEnum::VMValFloat {
                    val: VMValFloat { num: val.val }
                })
            }
            VMClassConstantInfoEnum::VMClassConstantInfoDouble { val } => {
                frame.borrow().operand_stack.borrow_mut().push(VMValEnum::VMValDouble {
                    val: VMValDouble { num: val.val }
                })
            }
            VMClassConstantInfoEnum::VMClassConstantInfoString { val } => {
                let jstring = VMHeap::create_jstring(&val.string, thread).unwrap();
                frame.borrow().operand_stack.borrow_mut().push(jstring);
            }
            VMClassConstantInfoEnum::VMClassConstantInfoClass { val } => {
                let mut rw_class_loader = thread.vm.class_loader.borrow_mut();

                let jclass = rw_class_loader.load_class(&val.name).unwrap();
                let class = rw_class_loader.load_class(&"java/lang/Class".to_string()).unwrap();
                let result = VMHeap::new_class_object(class.clone(), Some(jclass.clone()));
                if result.is_err() {
                    panic!("{},{},{}", file!(), line!(), result.err().unwrap());
                }
                frame.borrow().operand_stack.borrow_mut().push(result.unwrap());
            }
            _ => {
                panic!("{},{},{},常量类型异常", file!(), line!(), self.index);
            }
        }
    }

    fn to_string(&self) -> String {
        String::from("ldc")
    }
}